package com.easylinkin.linkappapi.common.utils;

import cn.hutool.core.date.DatePattern;
import com.easylinkin.bases.redis.util.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.concurrent.TimeUnit;

/**
 * 编码生成工具类
 *
 * @author zhengwen
 */
@Slf4j
public class BusinessSerialNoUtil {

    /**
     * 第一个数为时间戳，第二个数为当前时间戳下第几个
     */
    private static final long[] TIMESTAMP_SEQ = new long[2];

    private static final Object LOCK = new Object();

    /**
     * 业务编号生成公共方法
     *
     * @param redis     redis对象
     * @param prefix    前缀
     * @param splitStr  分割符
     * @param dayNoSize 序号长度
     *                  例如：zw-20151205001，zw为前缀，-为分割符，001为序列号即长度为3，如果是00001则长度是5
     * @return
     */
    public static String genSeqCode(RedisUtil redis, String prefix, String splitStr, int dayNoSize) {
        String thisDate = LocalDate.now().format(DateTimeFormatter.BASIC_ISO_DATE);
        if (StringUtils.isBlank(splitStr)) {
            splitStr = "";
        }
        String storeKey = String.join(splitStr, prefix, thisDate);

        String ind = (String) redis.get(storeKey);
        Long inc = 1L;
        if (StringUtils.isBlank(ind)) {
            redis.set(storeKey, inc + "", (int) TimeUnit.DAYS.toSeconds(1));
        } else {
            inc = Long.parseLong(ind) + 1;
            redis.set(storeKey, String.valueOf(inc), (int) TimeUnit.DAYS.toSeconds(1));
        }

        String increment = String.valueOf(Math.round(Math.pow(10, dayNoSize)) + inc).substring(1);
        //String code = String.join(splitStr, prefix, thisDate + increment);
        String code = String.join(splitStr, prefix, thisDate, increment);
        return code;
    }

    /**
     * 根据传入信息从redis取编号自增1，组织编号
     *
     * @param redis
     * @param prefix    前缀
     * @param dayNoSize 序号长度
     * @param splitStr  分割符
     * @param comStr    补全字符
     * @param comDir    补全方向
     * @param redisKey  redis的key
     */
    public static String genSeqCode(RedisUtil redis, String prefix, String splitStr, int dayNoSize, String redisKey, String comStr, String comDir) {
        String reStr = null;
        if (redis != null && StringUtils.isNotBlank(redisKey)) {
            String keyNo = (String) redis.get(redisKey);
            if (StringUtils.isBlank(keyNo)) {
                keyNo = "0";
            }
            int nKeyNo = Integer.parseInt(keyNo) + 1;
            redis.set(redisKey, String.valueOf(nKeyNo));
            if (StringUtils.isBlank(comStr)) {
                keyNo = "0";
            }
            String nKeyNoStr = completStrValue(comDir, comStr, dayNoSize, String.valueOf(nKeyNo));
            reStr = prefix + String.valueOf(splitStr) + nKeyNoStr;
        }
        return reStr;
    }

    /**
     * 补全字符串
     *
     * @param comDir：补全方向，before之前，after之后
     * @param comStr：补全字母
     * @param dayNoSize：总长度
     * @param nKeyNo:被补全字符串
     * @return 补全后的字符串
     */
    public static String completStrValue(String comDir, String comStr, int dayNoSize, String nKeyNo) {
        String reStr = String.valueOf(nKeyNo);
        if (StringUtils.isNotBlank(comDir) && StringUtils.isNotBlank(comStr)) {
            int len = reStr.length();
            int comLen = dayNoSize - len;
            if (comLen > 0) {
                StringBuffer sbf = new StringBuffer();
                for (int i = 0; i < comLen; i++) {
                    sbf.append(comStr);
                }
                switch (comDir) {
                    case "before":
                        reStr = sbf.toString() + reStr;
                        break;
                    case "after":
                        reStr = reStr + sbf.toString();
                        break;
                    default:
                }
            }
        }
        return reStr;
    }


    /**
     * 业务编号生成公共方法
     *
     * @param prefix   前缀
     * @param splitStr 分割符
     *                 例如：zw-20151205001，zw为前缀，-为分割符，001为序列号即长度为3，如果是00001则长度是5
     * @return String
     */
    public static String genSeqCode(String prefix, String splitStr) throws Exception {
        StringBuilder seqCode = new StringBuilder();
        seqCode.append(prefix).append(splitStr).append(getTimestampSeq());
        return seqCode.toString();
    }

    /**
     * <pre>
     *     获取时间戳流水号
     *     支持每秒10000的并发
     * </pre>
     *
     * @return String
     */
    private static String getTimestampSeq() throws Exception {
        String currentTime = DateUtil.format(new Date(), DatePattern.NORM_DATE_PATTERN);
        StringBuilder timestampStr = new StringBuilder();
        timestampStr.append(currentTime);
        synchronized (LOCK) {
            if (TIMESTAMP_SEQ[0] == 0) {
                TIMESTAMP_SEQ[0] = Long.parseLong(currentTime);
                TIMESTAMP_SEQ[1] = Long.parseLong("0");
            } else {
                String timestamp0 = Long.toString(TIMESTAMP_SEQ[0]);
                if (currentTime.equals(timestamp0)) {
                    TIMESTAMP_SEQ[1] = TIMESTAMP_SEQ[1] + 1;
                } else {
                    TIMESTAMP_SEQ[0] = Long.parseLong(currentTime);
                    TIMESTAMP_SEQ[1] = Long.parseLong("0");
                }
            }
            timestampStr.append(fillZeroLeft(4, TIMESTAMP_SEQ[1]));
        }
        return timestampStr.toString();
    }

    /**
     * 在左侧填充0
     *
     * @param numSize 数字总长度
     * @param num     被填充数
     * @return String
     */
    private static String fillZeroLeft(int numSize, long num) throws Exception {
        String first = Long.toString(num);
        StringBuilder builder = new StringBuilder();
        if (first.length() > numSize) {
            throw new RuntimeException("被填充数大小超过指定范围");
        } else {
            builder.append(first);
        }
        for (int i = builder.length(); i < numSize; i++) {
            builder.insert(0, "0");
        }
        return builder.toString();
    }
}
